package com.iussoft.receiveData.manager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apache.exception.BusinessException;
import com.apache.tools.DataMap;
import com.apache.tools.NumberUtils;
import com.apache.tools.StrUtil;
import com.iussoft.receiveData.manager.ReceiveManager;
import com.iussoft.tools.LoggerUtil;
import com.iussoft.tools.SendMsgTool;
import com.iussoft.tools.XMLUtil;
import org.apache.commons.collections.map.CaseInsensitiveMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: 数据解析Manager
 * @author: Hou Dayu
 * @date: Created in 2020/6/9
 */
@Component
public class DataAnalyzeManager {

    @Autowired
    private ReceiveManager receiveManager;
    @Autowired
    private SendMsgTool sendMsgTool;

    /**
     * 验证报文规则
     */
    private Map<String,String> checkMessage(String sourceMsg, String interfaceId, String sourceFile){
        LoggerUtil.info("数据预处理解阶段开始...");
        Map<String,String> rules = receiveManager.getRuleSite(interfaceId);
        if(!rules.isEmpty()){//验证解析规则
            if (StrUtil.isNotNull(rules.get("fileSuffix")) && StrUtil.isNotNull(sourceFile)) {//验证文后缀名
                if (!sourceFile.endsWith(rules.get("fileSuffix"))) {
                    throw new BusinessException("文件的后缀名不符合规则");
                }
            }
            if(StrUtil.isNotNull(rules.get("msgFormat"))){//验证报文格式
                String mf = rules.get("msgFormat");
                if("xml".equalsIgnoreCase(mf) && !XMLUtil.isXmlDocument(sourceMsg)){
                    throw new BusinessException("报文格式不符合xml规则");
                } else if("json".equalsIgnoreCase(mf) && !sendMsgTool.isJson(sourceMsg)){
                    throw new BusinessException("报文格式不符合json规则");
                }
            }
//            System.out.println("________----------------------->>>>"+sourceMsg.getBytes().length);
            double size = NumberUtils.divide(sourceMsg.getBytes().length, 1024, 4);
//            int size = sourceMsg.getBytes().length/1024;//变成Kb
            if(StrUtil.isNotNull(rules.get("msgSize"))){//验证报文大小
                String msgSize = rules.get("msgSize");
                double msize = Double.parseDouble(msgSize);
                if(size > msize){
                    throw new BusinessException("报文大小超过设定值("+msgSize+")kb");
                }
            } else {
                if(size > 1024){
                    throw new BusinessException("报文大小超过1M,需要人工处理");
                }
            }
        }
        return rules;
    }

    private JSONObject dataAnalyze(Map<String,String> rules, Map<String,Object> sourceMap, String interfaceId, String traceId){
        LoggerUtil.info("数据解析阶段开始...");
        Map<String,Object> formats = (Map)getInterfaceParams(interfaceId,"'resp'").get("body");
        String matchRule = "";
        String exceptionRule = "";
        if(rules != null && StrUtil.isNotNull(rules.get("matchRule"))){//验证匹配规则
            matchRule = rules.get("matchRule");
            exceptionRule = rules.get("exceptionRule");
        }

        if(null == formats || formats.isEmpty()){
            LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; errorMessage = 没有配置解析报文",traceId);
            JSONObject result = new JSONObject();
            result.putAll(sourceMap);
            return result;
        }
        Map<String,Object> data = new HashMap<>();
        if("02".equals(matchRule)){//是否忽略大小写
            formats = new CaseInsensitiveMap(formats);
        }
        Map<String,Object> rowkeys = new HashMap();
        for (Map.Entry<String, Object> map1 : sourceMap.entrySet()) {
            String nodeName = map1.getKey();
            Map<String,Object> node = (Map)formats.get(nodeName);
            if(node == null || node.isEmpty()){
                if("04".equals(matchRule)){//匹配不上中断
                    if(StrUtil.isNotNull(exceptionRule)) {
                        LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; nodeName = {}; nodeValue = {}; errorMessage = 节点不匹配中断",traceId, nodeName,String.valueOf(map1.getValue()));
                    }
                    throw new BusinessException("("+nodeName+")节点信息匹配不上");
                } else {
                    if("03".equals(matchRule)) {
                        LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; nodeName = {}; nodeValue = {}; errorMessage = {};", traceId, nodeName,String.valueOf(map1.getValue()), "节点匹配不上忽略继续");
                    }
                }
                continue;
            }
            Object val = map1.getValue();
            Map<String,Object> subpvl = (Map)node.get("children");
            if(null ==subpvl){
                subpvl=node;
            }
            if(val instanceof List){
                List<Map> sublist = (List)val;
                List<Map> maps = new ArrayList();
                for(int i=0;i<sublist.size();i++){
                    Map josn = sublist.get(i);
                    Map resultMap = buildMsgData(matchRule, exceptionRule, traceId, nodeName, josn, subpvl);
                    if(null != resultMap && !resultMap.isEmpty()){
                        maps.add(resultMap);
                    }
                }
                if(!maps.isEmpty()){
                    data.put(nodeName,maps);
                }
            } else if(val instanceof Map){
                Map<String,Object> smap = (Map)val;
                Map dd = buildMsgData(matchRule, exceptionRule, traceId, nodeName, smap, subpvl);
                if(null != dd && !dd.isEmpty()){
                    data.put(nodeName, dd.get(nodeName));
                    if(dd.size()>1) {
                        rowkeys.put(nodeName, getMapToString((Map) dd.get("rowkeyStr")));
                    }
                }
                continue;
            }
        }
        JSONObject result = new JSONObject();
        result.putAll(data);
        result.put("rowkeyStr",getMapToString(rowkeys));
        LoggerUtil.info("解析结果：",result);
        return result;
    }

    /**
     * map转str
     * @param map
     */
    public String getMapToString(Map<String,Object> map){
        //因为String拼接效率会很低的，所以转用StringBuilder。博主会在这篇博文发后不久，会更新一篇String与StringBuilder开发时的抉择的博文。
        StringBuilder sb = new StringBuilder();
        for (String key : map.keySet()) {
            // 参数值为空，则不参与签名 这个方法trim()是去空格
            sb.append(map.get(key));
        }
        return sb.toString();
    }

    /**
     * 遍历List类型数据
     * @param reqMap 请求参数
     * @param formats 定义参数
     */
    private List<Map> buildMapForList(List<Map> reqMap, Map<String,Object> formats, String matchRule,String exceptionRule,String traceId){
        List<Map> datas = new ArrayList<>();
        for(int i=0;i<reqMap.size();i++){
            Map<String,Object> map = reqMap.get(i);
            Map result = buildMapForMap(map,formats,matchRule,exceptionRule,traceId);
            if(!result.isEmpty()) {
                datas.add(result);
            }
        }
        return datas;
    }

    /**
     * 遍历Map类型数据
     * @param reqMap 请求参数
     * @param formats 定义参数
     */
    private Map<String,Object> buildMapForMap(Map<String,Object> reqMap, Map<String,Object> formats, String matchRule,String exceptionRule,String traceId){
        Map<String,Object> data = new HashMap<>();
        int count = 0;
        for (Map.Entry<String, Object> map : reqMap.entrySet()) {
            String nodeName = map.getKey();
            Map<String,Object> node = (Map)formats.get(nodeName);
            if(node == null || node.isEmpty()){
                if("04".equals(matchRule)){//匹配不上中断
                    if(StrUtil.isNotNull(exceptionRule)) {
                        LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; nodeName = {}; nodeValue = {}; errorMessage = 节点不匹配中断; level = {}",traceId, nodeName,String.valueOf(map.getValue()),"ERROR");
                    }
                    throw new BusinessException("("+nodeName+")节点信息匹配不上");
                } else{
                    count +=1;
                    if("03".equals(matchRule)) {
                        LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; nodeName = {}; nodeValue = {}; errorMessage = {}", traceId, nodeName,String.valueOf(map.getValue()), "节点不匹配");
                    } else if("01".equals(matchRule)){//报文节点数匹配
                        if (StrUtil.isNotNull(exceptionRule)) {
                            LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; nodeName = {}; nodeValue = {}; errorMessage = {}", traceId, nodeName,String.valueOf(map.getValue()),"节点数匹配不上");
                        }
                        throw new BusinessException("("+nodeName+")节点数匹配不上");
                    }
                    continue;
                }
            }
            Object obj = map.getValue();
            Map paras = null;
            if(null != node.get("children")){
                paras = (Map)node.get("children");
            }else{
                paras = node;
            }
            if(obj instanceof List){//遍历List类型数据
                List<Map> list = (List)obj;
                List<Map> redata = buildMapForList(list,paras,matchRule,exceptionRule,traceId);
                if(!StrUtil.isEmpty(redata)){
                    count = count + Integer.parseInt(String.valueOf(paras.get("formatsReqCount")));
                    paras.remove("formatsReqCount");
                }
                data.put(node.get("cloumEname").toString(),redata);//添加处理后结果
            } else if(obj instanceof Map){//遍历Map类型数据
                Map<String,Object> smap = (Map)obj;

                Map result = buildMsgData(matchRule, exceptionRule, traceId, nodeName, smap, paras);
                if(null != result && !result.isEmpty()){

                }
                data.put(node.get("cloumEname").toString(),result);//添加处理后结果
            }
        }
        return data;
    }

    private Map<String,Object> buildMsgData(String matchRule, String exceptionRule, String traceId,String nodeName, Map<String,Object> reqData, Map<String,Object> node){
        Map<String,Object> rowkeys = new HashMap();
        Map<String,Object> data = new HashMap();
        Map<String,Object> result = new HashMap();
        int count = 0;
        for(String key : reqData.keySet()){
            Map<String, Object> map = (Map) node.get(key);
            if(map == null || map.isEmpty()) {
                if("04".equals(matchRule)){//匹配不上中断
                    if(StrUtil.isNotNull(exceptionRule)) {
                        LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; nodeName = {}; nodeValue = {}; errorMessage = 节点不匹配中断; level = {}",traceId, key,String.valueOf(reqData.get(key)),"ERROR");
                    }
                    throw new BusinessException("("+key+")节点信息匹配不上中断");
                } else {
                    if("03".equals(matchRule)) {
                        LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; nodeName = {}; nodeValue = {}; errorMessage = {}", traceId, key,String.valueOf(reqData.get(key)), "节点不匹配");
                    }
                    continue;
                }
            }
            String cloumEname = String.valueOf(map.get("cloumEname"));
            Object obj = reqData.get(key);
            Map paras = (Map)map.get("children");;
            if(null == paras){
                paras = node;
            }
            if(obj instanceof List){//遍历List类型数据
                List<Map> list = (List)obj;
                List<Map> maps = new ArrayList();
                for(int i=0;i<list.size();i++){
                    Map josn = list.get(i);
                    Map resultMap = buildMsgData(matchRule, exceptionRule, traceId, key, josn, paras);
                    if(null != resultMap && !resultMap.isEmpty()){
                        maps.add(resultMap);
                    }
                }
                if(!maps.isEmpty()){
                    data.put(key,maps);
                }
            } else if(obj instanceof Map) {//遍历Map类型数据
                Map<String,Object> smap = (Map)obj;
                Map resultMap = buildMsgData(matchRule, exceptionRule, traceId, key, smap, paras);
                if(null != resultMap && !resultMap.isEmpty()){
                    data.put(key, resultMap.get(key));
                    if(resultMap.size()>1) {
                        rowkeys.put(key, getMapToString((Map) resultMap.get("rowkeyStr")));
                    }
                }
                continue;
            } else {
                String msg = String.valueOf(obj);
                if(msg.startsWith("{")){
                    JSONObject josn = JSON.parseObject(msg);
                    Map resultMap = buildMsgData(matchRule, exceptionRule, traceId, key, josn, paras);
                    if(null != resultMap && !resultMap.isEmpty()){
                        data.put(key, resultMap.get(key));
                        if(resultMap.size()>1) {
                            rowkeys.put(key, getMapToString((Map) resultMap.get("rowkeyStr")));
                        }
                    }
                    continue;
                } else if (msg.startsWith("[{")) {
                    JSONArray array = JSON.parseArray(msg);
                    List<Map> maps = new ArrayList();
                    for(int i=0;i<array.size();i++){
                        JSONObject josn = array.getJSONObject(i);
                        Map resultMap = buildMsgData(matchRule, exceptionRule, traceId, key, josn, paras);
                        if(null != resultMap && !resultMap.isEmpty()){
                            maps.add(resultMap);
                        }
                    }
                    if(!maps.isEmpty()){
                        data.put(key,maps);
                    }
                }
            }
            if("1".equals(map.get("ifUse"))) {//需要解析后留下的字段
                data.put(cloumEname, String.valueOf(reqData.get(key)));
                count += 1;
            }
            if("1".equals(map.get("ifRowKey"))){//需要拼装rowkey的字段
                rowkeys.put(cloumEname,reqData.get(key));
            }
        }
        if(count > 0) {//是否有节点
            if ("01".equals(matchRule)) {
                int nodeNum = Integer.parseInt(String.valueOf(node.get("nodecount")));
                if (nodeNum != count) {
                    if (StrUtil.isNotNull(exceptionRule)) {
                        LoggerUtil.warnSource("traceId = {}; exeSys = send; infoType = warning; nodeName = {}; nodeValue = {}; errorMessage = {}", traceId, nodeName, String.valueOf(reqData), "节点数匹配不上");
                    }
                    throw new BusinessException("(" + nodeName + ")节点数匹配不上");
                }
            }
        }
        if (!data.isEmpty()) {
            result.put(nodeName, data);
        }
        if (!rowkeys.isEmpty()) {
            result.put("rowkeyStr", rowkeys);
        }
        return result;
    }

    /**
     * 获取接口参数信息
     */
    public Map<String, Object> getInterfaceParams(String serverId,String formatType){
        long startTime = System.currentTimeMillis();
        List<DataMap> list = receiveManager.getInterfaceParams(serverId,formatType);
        if(StrUtil.isEmpty(list)){
            return new HashMap<>();
        }
        Map<String, Object> bodyMap = new HashMap<>();
        Map<String, Object> headerMap = new HashMap<>();
        Map<String, Object> urlMap = new HashMap<>();
        Map<String, Object> MenuList = new HashMap<>();
        int count = 0;
        Map<String,List<String>> group = getGroupNode(list);
        for(DataMap<String> vo: list){
            int num = 0;
            Map<String,Object> map = new HashMap<String,Object>();
            if("0".equals(vo.get("paramParent"))){//通过判断，0代表没有父级，也就是一级
                String paramEame = vo.get("paramEname");
                if("header".equals(vo.get("msgType")) || "params".equals(vo.get("msgType"))){
                    if("defaultRoot".equals(paramEame)){
                        Map<String, Object> data = getChildren(list, vo.get("infoId"), paramEame, vo.get("msgType"), group);
                        if (data != null) {
                            data.remove("nodecount");
                            if("header".equals(vo.get("msgType"))) {
                                headerMap.putAll(data);
                            }else{
                                urlMap.putAll(data);
                            }
                        }
                    }else {
                        if ("header".equals(vo.get("msgType"))) {
                            headerMap.put(paramEame, StrUtil.doNull(vo.get("defValue"), ""));
                        } else {
                            urlMap.put(paramEame, StrUtil.doNull(vo.get("defValue"), ""));
                        }
                    }
                } else {
                    map.put("paramEname",paramEame);
                    map.put("cloumEname",vo.get("cloumEname"));
                    map.put("ifNull",vo.get("ifNull"));
                    map.put("paramType",vo.get("paramType"));
                    map.put("ifUse",vo.get("ifUse"));
                    map.put("ifRowKey",vo.get("ifRowKey"));
                    if("1".equals(vo.get("ifSubParam"))) {
                        Map<String,Object> data = getChildren(list, vo.get("infoId"),paramEame,vo.get("msgType"), group);
                        if(data != null) {
                            map.put("children", data);//继续往一级下面遍历，调用下面的处理方法，放入树状结构
                            if(data != null){
                                int cdNum = Integer.parseInt(String.valueOf(data.get("nodecount")));
                                count = count + cdNum;
                                num += cdNum;
                            }
                            if("defaultRoot".equals(paramEame) && "json".equals(vo.get("interfaceRMFT"))){
                                bodyMap.putAll(data);
                            }
                        }
                    }
                    if("defaultRoot".equals(paramEame) && "json".equals(vo.get("interfaceRMFT"))){
                    } else {
                        num += 1;
                        map.put("nodecount",num);
                        bodyMap.put(paramEame, map);//先把一级存入结果
                    }
                }
            }
        }
        bodyMap.put("nodecount",count);
        MenuList.put("body",bodyMap);
        MenuList.put("header",headerMap);
        MenuList.put("params",urlMap);
        LoggerUtil.info("getInterfaceParams方法执行时间："+(System.currentTimeMillis()-startTime)+" ms");
        return MenuList;
    }

    //结果集转树状结构
    private Map<String, Object> getChildren(List<DataMap> data,String menuId,String parentEname,String msgType,Map<String,List<String>> group){//参数为数据库的（原数据，一级id）
        if(data==null || data.size()==0 || StrUtil.isNull(menuId)){
            return null;
        }
        Map<String, Object> menuList = new HashMap<>();
        int count = 0;
        for(DataMap<String> vo : data){
            if("F".equals(vo.get("flag"))){
                continue;
            }
            int num = 0;
            if(menuId.equals(vo.get("paramParent")) && msgType.equals(vo.get("msgType"))){//如果本级id与下面数据的父id相同，就说明是子父级关系
                String paramEame = vo.get("paramEname");
                if("header".equals(vo.get("msgType")) || "params".equals(vo.get("msgType"))){
                    if("header".equals(vo.get("msgType"))) {
                        menuList.put(paramEame, StrUtil.doNull(vo.get("defValue"), ""));
                    } else {
                        menuList.put(paramEame, StrUtil.doNull(vo.get("defValue"), ""));
                    }
                    vo.put("flag","F");
                } else {
                    List<String> nodes = group.get(vo.get("paramParent"));
                    List<String> sameNodes = getSameNode(nodes,paramEame);
                    List<Map> nodeList = new ArrayList();
                    for(String node : sameNodes){
                        String str[] = node.split(";");
                        DataMap<String> dm = data.get(Integer.parseInt(str[1]));
                        Map<String,Object> map = new HashMap();
                        map.put("paramEname",str[0]);
                        map.put("cloumEname",dm.get("cloumEname"));
                        map.put("ifNull",dm.get("ifNull"));
                        map.put("paramType",dm.get("paramType"));
                        map.put("ifUse",vo.get("ifUse"));
                        map.put("ifRowKey",vo.get("ifRowKey"));
                        dm.put("flag","F");
                        if("1".equals(dm.get("ifSubParam"))) {
                            Map<String,Object> children = getChildren(data, dm.get("infoId"),str[0],dm.get("msgType"),group);
                            if(children != null){
                                map.put("children",children);
                                int cdNum = Integer.parseInt(StrUtil.doNull(String.valueOf(children.get("nodecount")),"0"));
                                count = count + cdNum;
                                num += cdNum;
                            } else {
                                num +=1;
                                count = count +1;
                            }
                        } else {
                            num +=1;
                            count = count +1;
                        }
                        map.put("nodecount",num);
                        nodeList.add(map);
                    }
                    if(nodeList.size()==1){
                        menuList.put(paramEame, nodeList.get(0));
                    } else if(nodeList.size()>1) {
                        menuList.put(parentEname, nodeList);
                    }
                }
            }
        }
        menuList.put("nodecount",count);
        return menuList;
    }

    private Map<String,List<String>> getGroupNode(List<DataMap> data){
        Map<String,List<String>> mapData = new HashMap();
        for(int i=0; i<data.size();i++){
            DataMap<String> vo = data.get(i);
            String pid = vo.get("paramParent");
            if("0".equals(pid)){
                continue;
            }
            List<String> list = mapData.get(pid);
            if(null == list){
                list = new ArrayList();
            }
            list.add(vo.get("paramEname")+";"+i);
            mapData.put(pid,list);
        }
        return mapData;
    }

    private List<String> getSameNode(List<String> data,String nodeName){
        List<String> list = new ArrayList();
        for(String vo : data){
            if(vo.startsWith(nodeName+";")){
                list.add(vo);
            }
        }
        return list;
    }

    public Object getMapToHbase(String mergeParams,Map dataMap, Object obj){
        if(obj instanceof Map){
            Map<String,Object> ddm = (Map)obj;
            if(StrUtil.isNotNull(mergeParams)){
                String str[] = mergeParams.split(":");
                if(ddm.containsKey(str[0])){
                    String medatas[] = str[1].split(",");
                    Map<String,Object> copInfo = (Map)ddm.get(str[0]);
                    for(int i=0;i<medatas.length;i++){
                        if(StrUtil.isNotNull(String.valueOf(ddm.get(medatas[i])))) {
                            copInfo.put(medatas[i], String.valueOf(ddm.get(medatas[i])));
                        }
                    }
                    dataMap.putAll(copInfo);
                    return dataMap;
                }
            }
            for(String key: ddm.keySet()){
                Object obj2 = ddm.get(key);
                if(obj2 instanceof String){
                    if(null!= dataMap) {
                        dataMap.put(key, obj2);
                    }else{
                        return ddm;
                    }
                } else {
                    return getMapToHbase(mergeParams,dataMap,obj2);
                }
            }
        } else if(obj instanceof List){
            return obj;
        }
        return null;
    }

    public void getMapToHbase(Map dataMap,String putKey, Object obj){
        if(obj instanceof Map){
            Map<String,Object> ddm = (Map)obj;
            for(String key: ddm.keySet()){
                Object obj2 = ddm.get(key);
                if(obj2 instanceof String){
                    dataMap.put(key,obj2);
                } else {
                    getMapToHbase(dataMap,key,obj2);
                }
            }
        } else if(obj instanceof String){
            dataMap.put(putKey,obj);
        } else if(obj instanceof List){
            List list = (List)obj;
            for(int i=0;i<list.size();i++){
                Object obj2 = list.get(i);
                getMapToHbase(dataMap,"",obj2);
            }
        }
    }
}
